## 13.3. Shell Programming

In the section "Section 4.5, "Shells"" in Chapter 4, "Basic Unix Commands and Concepts", we discussed the various shells available for Linux, but something should be said about them in terms of programming. The differences come through most clearly when it comes to writing shell scripts. The Bourne shell and C shell command languages are slightly different, but the distinction is not obvious with most normal interactive use. In fact, many of the distinctions arise only when you attempt to use bizarre, little-known features of either shell, such as word substitution or some of the more oblique parameter expansion functions.

The most notable difference between Bourne and C shells is the form of the various flow-control structures, including `if …then` and `while` loops. In the Bourne shell, an `if …then` takes the form:

>     if list
>     then
>       commands
>     elif list
>     then
>       commands
>     else
>       commands
>     fi

where list is just a sequence of commands (more generally called "pipelines") to be used as the conditional expression for the `if` and `elif` (short for "else if") commands. The conditional is considered to be true if the exit status of the list is zero (unlike Boolean expressions in C, in shell terminology an exit status of zero indicates successful completion). The commands enclosed in the conditionals are simply commands to execute if the appropriate list is true. The `then` after each list must be on a new line to distinguish it from the list itself; alternately, you can terminate the list with a `;`. The same holds true for the commands.

An example is:

>     if [ "$PS1" ]; then
>       PS1="\h:\w% "
>     fi

This sequence checks to see whether the shell is a login shell (that is, whether the prompt variable `PS1` is set) and if so, resets the prompt to `\h:\w%`, which is a prompt expansion standing for the hostname followed by the current working directory. For example:

>     loomer:/home/loomer/mdw%

The `[…]` conditional appearing after the `if` is a `bash` built-in command, shorthand for `test`. The `test` command and its abbreviated equivalent provide a convenient mechanism for testing values of shell variables, string equivalence, and so forth. Instead of using `[…]`, you could call any set of commands after the `if`, as long as the last command's exit value indicates the value of the conditional.

Under `tcsh`, an `if …then` compound statement looks like the following:

>     if (expression) then
>       commands
>     else if (expression) then
>       commands
>     else
>       commands
>     endif

The difference here is that the expression after the `if` is an arithmetic or logical expression evaluated internally by `tcsh`, while with `bash` the conditional expression is a command, and the expression returns true or false based on the command's exit status. Within `bash`, using `test` or `[…]` is similar to an arithmetic expression as used in `tcsh`.

With `tcsh`, however, if you wish to run external commands within the expression, you must enclose the command in braces: `{command}`.

The equivalent of the previous `bash` sequence in `tcsh` is:

>     if ($?prompt) then
>       set prompt="%m:%/%% "
>     endif

where `tcsh` 's own prompt special characters have been used. As you can see, `tcsh` boasts a command syntax similar to the C language, and expressions are arithmetically and logically oriented. In `bash`, however, almost everything is an actual command, and expressions are evaluated in terms of exit status values. There are analogous features in either shell, but the approach is slightly different.

A similar change exists with the `while` loop. In `bash`, this takes the form:

>     while list
>     do
>       commands
>     done

You can negate the effect by replacing the word `while` with `until`. Again, list is just a command pipeline to be executed, and the exit status determines the result (zero for success and nonzero for failure). Under `tcsh` the loop looks like:

>     while (expression)
>       commands
>     end

where expression is a logical expression to be evaluated within `tcsh`.

This example should be enough to get a head start on understanding the overall differences of shell scripts under `bash` and `tcsh`. We encourage you to read the `bash` and `tcsh` manual pages (although they barely serve as a tutorial--more as a reference) and Info pages, if you have them available. Various books and tutorials on using these two shells are available as well; in fact, any book on shell programming will do, and you can interpolate the advanced features of `bash` and `tcsh` over the standard Bourne and C shells using the manual pages. Learning the bash Shell by Cameron Newham and Bill Rosenblatt and Using csh and tcsh by Paul DuBois are also good investments.

Copyright © 2001 O'Reilly & Associates. All rights reserved.